package JavaLab.Collections;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

public class MyArrayList implements MyList, RandomAccess{

	private static final int DEFAULT_CAPACITY = 10;
	
	private Object[] data;
	
	private int size;
	
	public MyArrayList(){
		this.data = new Object[DEFAULT_CAPACITY];
	}
	
	public MyArrayList(int initialCapacity) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.data = new Object[initialCapacity];
    }
	
	public MyArrayList(MyList list){
		ensureCapacity(list.size());
		System.arraycopy(list.toArray(), 0, data, 0, list.size());
	}
	
	public void add(Object e) {
		ensureCapacity(size + 1);
		data[size++] = e;
	}

	public void add(int index, Object e) {
		checkElementIndexForInsert(index);
		ensureCapacity(size + 1);
		System.arraycopy(data, index, data, index + 1, size - index);
		data[index] = e;
		size++;
	}

	public void addAll(Object[] e) {
		ensureCapacity(size + e.length);
		System.arraycopy(e, 0, data, size, e.length);
		size += e.length;
	}

	public void addAll(int index, Object[] e) {
		checkElementIndexForInsert(index);
		ensureCapacity(size + e.length);
		System.arraycopy(data, index, data, index + size, size - index);
		System.arraycopy(e, 0, data, index, e.length);
		size += e.length;
	}

	public Object get(int index) {
		checkElementIndex(index);
		return data[index];
	}

	public Object remove(int index) {
		checkElementIndex(index);
		Object res = data[index];
		System.arraycopy(data, index + 1, data, index, size - index);
		size--;
		return res;
	}

	public void clear() {
		for(int i = 0; i < data.length; i++){
			data[i] = null;
		}
		size = 0;
	}

	public boolean isEmpty() {
		return size == 0;
	}

	public void set(int index, Object e) {
		checkElementIndexForInsert(index);
		data[index] = e;
	}

	public int indexOf(Object o) {
		if (o == null) {
            for (int i = 0; i < size; i++)
                if (data[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(data[i]))
                    return i;
        }
        return -1;
	}

	public int size() {
		return size;
	}

	public Object[] toArray() {
		return Arrays.copyOf(data, size);
	}

	public Iterator iterator() {
		return new Itr();
	}
	
	public void ensureCapacity(int minCapacity){
		int currCapacity = data.length;
		int toCapacity = currCapacity;
		if(currCapacity < minCapacity){
			while(toCapacity < minCapacity){
				toCapacity *= 2;
			}
		}
		Arrays.copyOf(data, toCapacity);
	}
	
	public void trimToSize(){
		if (size < data.length) {
            data = Arrays.copyOf(data, size);
        }
	}
	
	private void checkElementIndex(int index){
		if(index < 0 || index >= size)
			throw new MyIndexOutOfBoundsException();
	}
	
	private void checkElementIndexForInsert(int index){
		if(index < 0 || index > size)
			throw new MyIndexOutOfBoundsException();
	}

	private class Itr implements Iterator {
        int cursor;	//index of the next element to return

        public boolean hasNext() {
            return cursor != size;
        }

        public Object next(){
        	if(cursor >= size)
        		throw new NoSuchElementException();
        	return data[cursor++];
        }
        
        public void remove(){
        	MyArrayList.this.remove(cursor - 1);
        }
	}
}
